<template>
	<div class="drag-verify-container">
		<div :style="dragVerifyImgStyle" class="drag-verify-container_img">
			<img ref="checkImg" :src="imgsrc" class="check-img" :class="{ goOrigin: state.isOk }" @load="checkimgLoaded" :style="state.imgStyle" alt="" />
			<div class="tips success" v-if="showTips && isPassing">{{ successTip }}</div>
			<div class="tips danger" v-if="showTips && !isPassing && state.showErrorTip">{{ failTip }}</div>
		</div>
		<div
			ref="dragVerify"
			class="drag_verify"
			:style="dragVerifyStyle"
			@mousemove="dragMoving"
			@mouseup="dragFinish"
			@mouseleave="dragFinish"
			@touchmove="dragMoving"
			@touchend="dragFinish"
		>
			<div class="dv_progress_bar" :class="{ goFirst2: state.isOk }" ref="progressBar" :style="progressBarStyle">
				{{ successMessage }}
			</div>
			<div class="dv_text" :style="textStyle" ref="message">
				{{ message }}
			</div>

			<div
				class="dv_handler dv_handler_bg"
				:class="{ goFirst: state.isOk }"
				@mousedown="dragStart"
				@touchstart="dragStart"
				ref="handler"
				:style="handlerStyle"
			>
				<i :class="handlerIcon"></i>
			</div>
		</div>
	</div>
</template>
<script lang="ts">
import { defineProps, onMounted, nextTick, computed, getCurrentInstance, reactive, watch, defineEmits } from 'vue'
export default {
	name: 'dragVerifyRotate'
}
</script>
<script setup lang="ts">
const define = defineProps({
	isPassing: {
		type: Boolean,
		default: false,
	},
	width: {
		type: Number,
		default: 250,
	},
	height: {
		type: Number,
		default: 40,
	},
	text: {
		type: String,
		default: 'swiping to the right side',
	},
	successText: {
		type: String,
		default: 'success',
	},
	background: {
		type: String,
		default: '#eee',
	},
	progressBarBg: {
		type: String,
		default: '#76c61d',
	},
	completedBg: {
		type: String,
		default: '#76c61d',
	},
	circle: {
		type: Boolean,
		default: false,
	},
	radius: {
		type: String,
		default: '4px',
	},
	handlerIcon: {
		type: String,
	},
	successIcon: {
		type: String,
	},
	handlerBg: {
		type: String,
		default: '#fff',
	},
	textSize: {
		type: String,
		default: '14px',
	},
	textColor: {
		type: String,
		default: '#333',
	},
	imgsrc: {
		type: String,
	},
	showTips: {
		type: Boolean,
		default: true,
	},
	successTip: {
		type: String,
		default: '验证通过',
	},
	failTip: {
		type: String,
		default: '验证失败',
	},
	diffDegree: {
		type: Number,
		default: 10,
	},
	minDegree: {
		type: Number,
		default: 90,
	},
	maxDegree: {
		type: Number,
		default: 270,
	},
})
const props = getCurrentInstance() as any
const state = reactive({
	isMoving: false,
	x: 0,
	isOk: false,
	showBar: false,
	showErrorTip: false,
	ranRotate: 0,
	cRotate: 0,
	imgStyle: {},
})
const emit = defineEmits(['handlerMove', 'update:isPassing', 'passfail', 'passcallback', 'refresh'])
onMounted(() => {
	nextTick(() => {
		const dragEl = props.refs.dragVerify
		dragEl.style.setProperty('--textColor', define.textColor)
		dragEl.style.setProperty('--width', Math.floor(define.width / 2) + 'px')
		dragEl.style.setProperty('--pwidth', -Math.floor(define.width / 2) + 'px')
	})
})
const handlerStyle = computed(() => {
	return {
		width: define.height + 'px',
		height: define.height + 'px',
		background: define.handlerBg,
	}
})
const message = computed(() => {
	return define.isPassing ? '' : define.text
})
const successMessage = computed(() => {
	return define.isPassing ? define.successText : ''
})
const dragVerifyStyle = computed(() => {
	return {
		width: define.width + 'px',
		height: define.height + 'px',
		lineHeight: define.height + 'px',
		background: define.background,
		borderRadius: define.circle ? define.height / 2 + 'px' : define.radius,
	}
})
const dragVerifyImgStyle = computed(() => {
	return {
		width: define.width + 'px',
		height: define.width + 'px'
	}
})
const progressBarStyle = computed(() => {
	return {
		background: define.progressBarBg,
		height: define.height + 'px',
		borderRadius: define.circle ? define.height / 2 + 'px 0 0 ' + define.height / 2 + 'px' : define.radius,
	}
})
const textStyle = computed(() => {
	return {
		height: define.height + 'px',
		width: define.width + 'px',
		fontSize: define.textSize,
	}
})
const factor = computed(() => {
	//避免指定旋转角度时一直拖动到最右侧才验证通过
	if (define.minDegree == define.maxDegree) {
		return Math.floor(1 + Math.random() * 6) / 10 + 1
	}
	return 1
})
const checkimgLoaded = function () {
	//生成旋转角度
	var minDegree = define.minDegree
	var maxDegree = define.maxDegree
	var ranRotate = Math.floor(minDegree + Math.random() * (define.maxDegree - define.minDegree)) //生成随机角度
	state.ranRotate = ranRotate
	state.imgStyle = {
		transform: `rotateZ(${ranRotate}deg)`,
	}
}
interface MouseEvent {
	pageX?: any,
	touches?: any
}
const dragStart = function (e: MouseEvent) {
	if (!define.isPassing) {
		state.isMoving = true
		state.x = e.pageX || e.touches[0].pageX
	}
	state.showBar = true
	state.showErrorTip = false
	emit('handlerMove')
}
const dragMoving = function (e: MouseEvent) {
	if (state.isMoving && !define.isPassing) {
		var _x = (e.pageX || e.touches[0].pageX) - state.x
		var handler = props.refs.handler
		handler.style.left = _x + 'px'
		props.refs.progressBar.style.width = _x + define.height / 2 + 'px'
		var cRotate = Math.ceil((_x / (define.width - define.height)) * define.maxDegree * factor.value)
		state.cRotate = cRotate
		var rotate = state.ranRotate - cRotate
		state.imgStyle = {
			transform: `rotateZ(${rotate}deg)`,
		}
	}
}
const dragFinish = function (e: MouseEvent) {
	if (state.isMoving && !define.isPassing) {
		if (Math.abs(state.ranRotate - state.cRotate) > define.diffDegree) {
			state.isOk = true
			state.imgStyle = {
				transform: `rotateZ(${state.ranRotate}deg)`,
			}
			setTimeout(function () {
				props.refs.handler.style.left = '0'
				props.refs.progressBar.style.width = '0'
				state.isOk = false
			}, 500)
			state.showErrorTip = true
			emit('passfail')
		} else {
			passVerify()
		}
		state.isMoving = false
	}
}
const passVerify = function () {
	emit('update:isPassing', true)
	state.isMoving = false
	var handler = props.refs.handler
	handler.children[0].className = define.successIcon
	props.refs.progressBar.style.background = define.completedBg
	props.refs.message.style['-webkit-text-fill-color'] = 'unset'
	props.refs.message.style.animation = 'slidetounlock2 3s infinite'
	props.refs.progressBar.style.color = '#fff'
	props.refs.progressBar.style.fontSize = define.textSize
	emit('passcallback')
}
// const reset = function () {
// 	reImg()
// 	checkimgLoaded()
// }
const reImg = function () {
	emit('update:isPassing', false)
	state.isMoving = false
	state.x = 0
	state.isOk = false
	state.showBar = false
	state.showErrorTip= false
	state.ranRotate= 0
	state.cRotate= 0
	state.imgStyle= {}
	var handler = props.refs.handler
	var message = props.refs.message
	handler.style.left = '0'
	props.refs.progressBar.style.width = '0'
	handler.children[0].className = define.handlerIcon
	message.style['-webkit-text-fill-color'] = 'transparent'
	message.style.animation = 'slidetounlock 3s infinite'
	message.style.color = define.background
}
// const refreshimg = function () {
// 	emit('refresh')
// }
watch(
	() => define.imgsrc,
	() => reImg()
)
</script>
<style lang="scss" scoped>
.drag_verify {
	position: relative;
	background-color: #e8e8e8;
	text-align: center;
	overflow: hidden;
}
.drag_verify .dv_handler {
	position: absolute;
	top: 0px;
	left: 0px;
	cursor: move;
}
.drag_verify .dv_handler i {
	color: #666;
	padding-left: 0;
	font-size: 16px;
}
.drag_verify .dv_handler .el-icon-circle-check {
	color: #6c6;
	margin-top: 9px;
}
.drag_verify .dv_progress_bar {
	position: absolute;
	height: 34px;
	width: 0px;
}
.drag_verify .dv_text {
	position: absolute;
	top: 0px;
	color: transparent;
	-moz-user-select: none;
	-webkit-user-select: none;
	user-select: none;
	-o-user-select: none;
	-ms-user-select: none;
	background: -webkit-gradient(
		linear,
		left top,
		right top,
		color-stop(0, var(--textColor)),
		color-stop(0.4, var(--textColor)),
		color-stop(0.5, #fff),
		color-stop(0.6, var(--textColor)),
		color-stop(1, var(--textColor))
	);
	-webkit-background-clip: text;
	-webkit-text-fill-color: transparent;
	-webkit-text-size-adjust: none;
	animation: slidetounlock 3s infinite;
}
.drag_verify .dv_text * {
	-webkit-text-fill-color: var(--textColor);
}
.goFirst {
	left: 0px !important;
	transition: left 0.5s;
}
.goOrigin {
	transition: transform 0.5s;
}
.goKeep {
	transition: left 0.2s;
}
.goFirst2 {
	width: 0px !important;
	transition: width 0.5s;
}
.drag-verify-container {
	position: relative;
	line-height: 0;
	border-radius: 50%;
	&_img {
		position: relative;
		overflow: hidden;
		border-radius: 50%;
	}
}
.move-bar {
	position: absolute;
	z-index: 100;
}
.clip-bar {
	position: absolute;
	background: rgba(255, 255, 255, 0.8);
}
.refresh {
	position: absolute;
	right: 5px;
	top: 5px;
	cursor: pointer;
	font-size: 20px;
	z-index: 200;
}
.tips {
	position: absolute;
	bottom: 25px;
	height: 20px;
	line-height: 20px;
	text-align: center;
	width: 100%;
	font-size: 12px;
	z-index: 200;
}
.tips.success {
	background: rgba(255, 255, 255, 0.6);
	color: green;
}
.tips.danger {
	background: rgba(0, 0, 0, 0.6);
	color: yellow;
}
.check-img {
	width: 100%;
	border-radius: 50%;
}
</style>
<style>
@-webkit-keyframes slidetounlock {
	0% {
		background-position: var(--pwidth) 0;
	}
	100% {
		background-position: var(--width) 0;
	}
}
@-webkit-keyframes slidetounlock2 {
	0% {
		background-position: var(--pwidth) 0;
	}
	100% {
		background-position: var(--pwidth) 0;
	}
}
</style>
